package com.lry.pda.bottom.operation;

import com.lry.pda.Lexer;
import com.lry.pda.Register;
import com.lry.pda.topdown.SymbolDefine;

import java.util.Map;
import java.util.Stack;

public class LRValueParser {

    private Lexer lexer;
    private Register register = new Register();
    private Stack<Integer> stack = new Stack<>();//存储节点编号的状态堆栈
    private Stack<String> valueStack = new Stack<>();
    private Stack<Integer> intStack = new Stack<>();

    private Map<Integer, Map<Integer,Integer>> lrTable;
    private int inputToken;
    private String text;

    public LRValueParser(Lexer lexer){
        this.lexer = lexer;
        this.lexer.input();
        this.lexer.advance();
        this.inputToken = this.lexer.lookAhead;
        stack.push(0);//初始为0节点
        lrTable = StateManager.getSelf().getLRTable();
    }

    private Integer getAction(Integer currentState, Integer currentInput) {
        Map<Integer, Integer> jump = lrTable.get(currentState);
        if (jump != null) {
            Integer next = jump.get(currentInput);
            if (next != null) {
                return next;
            }
        }

        return null;
    }

    public void parse(){
        Integer action = null;

        while(true){
            action = getAction(stack.peek(), inputToken);

            if (action == null) {
                //解析出错
                System.err.println("The input is denied");
                return;
            }

            if(action==0){
                System.out.println("The input can be accepted");
                return;
            }else if(action > 0){
                //shift 操作
                stack.push(action);//压入下一个节点编号
                if (SymbolDefine.isSymbolTerminals(inputToken)) {
                    text = lexer.yytext;
                    lexer.advance();
                }
                inputToken = lexer.lookAhead;
            }else {
                int number = - action;
                Production product = ProductionManager.getSelf().getProductionByNumber(number);
                switch (number){
//                    expr -> expr + term
//                    term -> term * factor
                    case 1:

                        String t1 = valueStack.pop();
                        String t0 = valueStack.peek();
                        System.out.println(t0 +" += " +t1);
                        register.free(t1);

                        int int1 = intStack.pop();
                        int int0 = intStack.pop();
                        int0 += int1;
                        System.out.println(t0 +" = "+int0);
                        intStack.push(int0);

                        break;
                    case 3:

                        t1 = valueStack.pop();
                        t0 = valueStack.peek();
                        System.out.println(t0 +" *= " +t1);
                        register.free(t1);

                        int1 = intStack.pop();
                        int0 = intStack.pop();
                        int0 *= int1;
                        System.out.println(t0 +" = "+int0);
                        intStack.push(int0);

                        break;
                        //expr -> term
                    //term -> factor
                    case 2:
                    case 4:
                        break;

                        //factor -> ( expr )
                    case 5:
                        break;

                        //factor -> NUM
                    case 6:
                        String name = register.getName();
                        System.out.println(name +" = " +text);
                        valueStack.push(name);
                        intStack.push(Integer.valueOf(text));
                        break;

                }

                inputToken = product.getLeft();

                int rightSize = product.getRights().size();
                while (rightSize > 0) {
                    stack.pop();
                    rightSize--;
                }
            }
        }
    }

    public static void main(String[] args) {
        ProductionManager productionManager = ProductionManager.getSelf();
        productionManager.init();

        StateManager stateManager = StateManager.getSelf();
        stateManager.buildTransitionStateMachine();

        System.out.println("Input string for parsing:");
        LRValueParser lrParser = new LRValueParser(new Lexer());
        lrParser.parse();
    }
}
